library ieee;
use ieee.std_logic_1164.all;
use IEEE.NUMERIC_STD.all;
use ieee.std_logic_unsigned.all;
use work.typeDefinitions.all;

entity dcache_ctrl is
  port
    (
      clk, nReset                : in  std_logic;
      -- CPU side
      halt                       : in  std_logic;
      halt_out                   : out std_logic;
      dmemREN, dmemWEN           : in  std_logic;
      dmemAddr                   : in  std_logic_vector(31 downto 0);
      dmemWriteData              : in  std_logic_vector(31 downto 0);
      dmemReadData               : out std_logic_vector(31 downto 0);
      dmemWait                   : out std_logic;
      -- Arbiter side
      arbREN                     : out std_logic;  -- dcache read request
      arbWEN                     : out std_logic;  -- dcache write request
      arbWait                    : in  std_logic;  -- dcache must wait if 1
      arbAddr                    : out std_logic_vector(31 downto 0);  -- dcache address being read
      arbReadData                : in  std_logic_vector(31 downto 0);  -- dcache data to be read
      arbWriteData               : out std_logic_vector(31 downto 0);  -- dcache data to be written
      -- dcache side (sets 1 and 2)
      s1_tag, s2_tag             : out std_logic_vector(24 downto 0);
      s1_tagOut, s2_tagOut       : in  std_logic_vector(24 downto 0);
      s1_index, s2_index         : out std_logic_vector(3 downto 0);
      s1_wdat, s2_wdat           : out std_logic_vector(63 downto 0);  -- write data to be written on datWEN
      s1_wDirty, s2_wDirty       : out std_logic;  -- dirty bit to be written on datWEN
      s1_datWEN, s2_datWEN       : out std_logic;
      s1_rdat, s2_rdat           : in  std_logic_vector(63 downto 0);
      s1_rHit, s2_rHit           : in  std_logic;
      s1_rDirty, s2_rDirty       : in  std_logic;
      s1_rRecent, s2_rRecent     : in  std_logic;
      s1_wRecent, s2_wRecent     : out std_logic;
      s1_recentWEN, s2_recentWEN : out std_logic;
      -- dcache coherence
      s1_rMSI, s2_rMSI           : in  coherenceState;
      s1_busrMSI, s2_busrMSI     : in  coherenceState;
      s1_wMSI, s2_wMSI           : out coherenceState;
      s1_buswMSI, s2_buswMSI     : out coherenceState;
      s1_MSIWEN, s2_MSIWEN       : out std_logic;
      s1_busMSIWEN, s2_busMSIWEN : out std_logic;
      s1_busHit, s2_busHit       : in  std_logic;
      s1_busDirty, s2_busDirty   : in  std_logic;
      s1_busrdat, s2_busrdat     : in  std_logic_vector(63 downto 0);
      s1_busTag, s2_busTag       : out std_logic_vector(24 downto 0);
      s1_busIndex, s2_busIndex   : out std_logic_vector(3 downto 0);
      -- bus side (coherence signals)
      TxBusOp                    : out memBusOp;
      TxBusAddr                  : out std_logic_vector(31 downto 0);
      TxBusResp                  : out memBusResp;
      TxBusData                  : out std_logic_vector(63 downto 0);
      RxBusOp                    : in  memBusOp;
      RxBusAddr                  : in  std_logic_vector(31 downto 0);
      RxBusResp                  : in  memBusResp;
      RxBusData                  : in  std_logic_vector(63 downto 0);
      -- coco override signal
      cocoOverride								: in std_logic
      );
end dcache_ctrl;

architecture dcache_ctrl_arch of dcache_ctrl is

  type   state_type is(idle, s1_snoop, s2_snoop, busUpgrade, s1_wb1, s1_wb2, s1_read1, s1_read2, s2_wb1, s2_wb2, s2_read1, s2_read2, halt_halted, halt_check1, halt_check2, halt_inc, halt_s1wb1, halt_s1wb2, halt_s2wb1, halt_s2wb2);
  signal currState, nextState : state_type;

  type   bus_state_type is (idle, respond1, respond2);
  signal busState, nextBusState : bus_state_type;

  signal t_tag          : std_logic_vector(24 downto 0);
  signal t_index        : std_logic_vector(3 downto 0);
  signal halt_index     : std_logic_vector(3 downto 0);
  signal halt_indexNext : std_logic_vector(3 downto 0);
  signal t_wordSelect   : std_logic;
  signal t_chosenSet    : std_logic;    -- 0=set1, 1=set2
  signal t_chosenData   : std_logic_vector(63 downto 0);
  signal t_chosenWord   : std_logic_vector(31 downto 0);
  signal t_chosenHit    : std_logic;
  signal t_chosenMSI    : coherenceState;

  signal t_chosenBusSet    : std_logic;  -- 0=set1, 1=set2
  signal t_chosenBusData   : std_logic_vector(63 downto 0);
  signal t_chosenBusHit    : std_logic;
  signal t_chosenBusMSI    : coherenceState;
  signal t_busRespGo       : std_logic;  -- output a bus response
  signal t_currentHitState : std_logic;

  signal t_arbAddr : std_logic_vector(31 downto 0);

  signal t_readData, t_readDataNext : std_logic_vector(31 downto 0);

  signal s1_priority, s2_priority : std_logic_vector(2 downto 0);

  signal t_nextBusMSI : coherenceState;

  signal DOUBLE_HIT_ERROR     : std_logic;
  signal BUS_DOUBLE_HIT_ERROR : std_logic;


  signal s1_tempI, s2_tempI : std_logic;
  
begin

  t_tag        <= dmemAddr(31 downto 7);
  t_index      <= dmemAddr(6 downto 3);
  t_wordSelect <= dmemAddr(2);
  s1_tag       <= t_tag;
  s2_tag       <= t_tag;

  arbAddr <= t_arbAddr;

  -- selects the data from either set
  chooseS1S2 : process(s1_rHit, s2_rHit, s1_rRecent, s2_rRecent)
  begin
    t_chosenSet      <= '0';
    DOUBLE_HIT_ERROR <= '0';
    if(s1_rHit = '1' and s2_rHit = '0') then
      t_chosenSet <= '0';
    elsif(s1_rHit = '0' and s2_rHit = '1') then
      t_chosenSet <= '1';
    elsif(s1_rHit = '1' and s2_rHit = '1') then
      if(s1_rRecent = '1') then
        t_chosenSet <= '0';
      elsif(s2_rRecent = '1') then
        t_chosenSet <= '1';
      end if;
      DOUBLE_HIT_ERROR <= '1';
    else
      t_chosenSet <= '0';
    end if;
  end process;
  with t_chosenSet select t_chosenData <= s2_rdat when '1',
                                          s1_rdat when others;
  with t_chosenSet select t_chosenHit <= s2_rHit when '1',
                                         s1_rHit when others;
  with t_chosenSet select t_chosenMSI <= s2_rMSI when '1',
                                         s1_rMSI when others;
  with t_wordSelect select t_chosenWord <= t_chosenData(63 downto 32) when '0',
                                           t_chosenData(31 downto 0) when others;
  dmemReadData <= t_chosenWord;         -- send chosen word to output

  s1_busTag   <= RxBusAddr(31 downto 7);
  s2_busTag   <= RxBusAddr(31 downto 7);
  s1_busIndex <= RxBusAddr(6 downto 3);
  s2_busIndex <= RxBusAddr(6 downto 3);

  -- select bus data from either set
  chooseBusS1S2 : process(s1_busHit, s2_busHit)
  begin
    t_chosenBusSet       <= '0';
    BUS_DOUBLE_HIT_ERROR <= '0';
    if(s1_busHit = '1' and s2_busHit = '0') then
      t_chosenBusSet <= '0';
    elsif(s1_busHit = '0' and s2_busHit = '1') then
      t_chosenBusSet <= '1';
    elsif(s1_busHit = '1' and s2_busHit = '1') then
      BUS_DOUBLE_HIT_ERROR <= '1';
    end if;
  end process;
  with t_chosenBusSet select t_chosenBusData <= s2_busrdat when '1',
                                                s1_busrdat when others;
  with t_chosenBusSet select t_chosenBusHit <= s2_busHit when '1',
                                               s1_busHit when others;
  with t_chosenBusSet select t_chosenBusMSI <= s2_busrMSI when '1',
                                               s1_busrMSI when others;

  -- what is the next MSI state for the chosen set (relative to bus request)?
  bus_nextMSI : process(t_chosenBusMSI, t_chosenBusHit, RxBusOp)
  begin
    t_nextBusMSI <= t_chosenBusMSI;
    if(t_chosenBusHit = '1') then
      if(RxBusOp = bus_RdX) then
        t_nextBusMSI <= co_I;
      elsif(RxBusOp = bus_Rd) then
        t_nextBusMSI <= co_S;
      end if;
    end if;
  end process;
  s1_buswMSI <= t_nextBusMSI;  -- connect these (only written when WEN is 1)
  s2_buswMSI <= t_nextBusMSI;

  -- bus state machine
  bus_state : process(clk, nReset, nextBusState)
  begin
    if(nReset = '0') then
      busState <= idle;
    elsif(rising_edge(clk)) then
      busState <= nextBusState;
    end if;
  end process;

  -- hold bus response logic
  hold_bus_resp : process(cocoOverride, RxBusAddr, dmemWEN, dmemREN, t_tag, t_index, t_arbAddr, RxBusOp)
  begin
    t_busRespGo <= '0';
		if( cocoOverride = '0' ) then	
			if(
				(((RxBusAddr(31 downto 3)&"000") = (t_tag&t_index&"000")) and (dmemREN = '1' or dmemWEN = '1'))
				or
				((RxBusAddr(31 downto 3)&"000") = (t_arbAddr(31 downto 3)&"000"))
				) then
				t_busRespGo <= '0';               -- hold the bus response
			elsif(RxBusOp /= bus_txnop) then
				t_busRespGo <= '1';
			end if;
		elsif( cocoOverride = '1' ) then
			t_busRespGo <= '1';
		end if;
  end process;

  -- bus nextstate logic
  bus_nextstate : process(busState, RxBusOp, t_busRespGo, t_chosenBusSet, s2_busHit, s1_busHit)
  begin
    t_currentHitState <= s1_busHit;
    nextBusState      <= busState;
    --t_currentHitState <= '0';
    case busState is
      when idle =>
        if(RxBusOp /= bus_txnop and t_busRespGo = '1') then
          if(t_chosenBusSet = '1') then
            nextBusState      <= respond2;
            t_currentHitState <= s2_busHit;
          else
            nextBusState      <= respond1;
            t_currentHitState <= s1_busHit;
          end if;
        else
          nextBusState <= idle;
        end if;
      when respond1 =>
--                              if( t_busRespGo='1' ) then
--                                      nextBusState <= idle;
--                              else
--                                      nextBusState <= respond1;
--                              end if;
        t_currentHitState <= s1_busHit;
        nextBusState      <= idle;
      when respond2 =>
--                              if( t_busRespGo='1' ) then
--                                      nextBusState <= idle;
--                              else
--                                      nextBusState <= respond2;
--                              end if;
        t_currentHitState <= s2_busHit;
        nextBusState      <= idle;
      when others =>
        nextBusState <= busState;
    end case;
  end process;

  -- bus output logic
  bus_outp : process(busState, t_chosenBusHit, t_busRespGo, t_chosenBusSet, t_currentHitState)
  begin
    TxBusResp    <= bus_rxnop;
    s1_busMSIWEN <= '0';
    s2_busMSIWEN <= '0';
    case busState is
      when idle =>
        TxBusResp    <= bus_rxnop;
        s1_busMSIWen <= '0';
        s2_busMSIWen <= '0';
      when respond1 =>
                                        --if( t_busRespGo = '1' ) then
                                        --if( t_chosenBusHit='1' ) then
        if(t_currentHitState = '1') then
                                        -- flush
          TxBusResp    <= bus_flush;
          s1_busMSIWen <= '1';
        else
                                        -- flush NF
          TxBusResp <= bus_flushNF;
        end if;
                                        --end if;
      when respond2 =>
                                        --if( t_busRespGo = '1' ) then
                                        --if( t_chosenBusHit='1' ) then
        if(t_currentHitState = '1') then
                                        -- flush
          TxBusResp    <= bus_flush;
          s2_busMSIWen <= '1';
        else
                                        -- flush NF
          TxBusResp <= bus_flushNF;
        end if;
        --end if;
    end case;
  end process;
  with t_busRespGo select TxBusData <= t_chosenBusData when '1',
                                       x"0000000000000000" when others;

  -- dcache state machine
  dcache_state : process(clk, nReset, nextState, halt_indexNext, t_readDataNext)
  begin
    if(nReset = '0') then
      currState  <= idle;
      t_readData <= x"00000000";
      halt_index <= (others => '0');
    elsif(rising_edge(clk)) then
      currState  <= nextState;
      halt_index <= halt_indexNext;
      t_readData <= t_readDataNext;
    end if;
  end process dcache_state;

  -- dcache sate machine next state logic
  nexttstate : process(dmemREN, dmemWEN, dmemAddr, dmemWriteData, s1_rdat, s2_rdat, s1_rHit, s2_rHit, s1_rDirty, s2_rDirty, s1_rRecent, s2_rRecent, arbWait, arbReadData, halt, halt_index, currState, t_chosenHit, s1_priority, s2_priority, t_readDataNext, t_readData, t_chosenMSI, RxBusResp, s1_rMSI, s2_rMSI, s1_tempI, s2_tempI)
  begin
    nextState      <= currState;
    t_readDataNext <= t_readData;
    halt_indexNext <= halt_index;

    if(s1_rMSI = co_I) then
      s1_tempI <= '0';
    else
      s1_tempI <= '1';
    end if;
    if(s2_rMSI = co_I) then
      s2_tempI <= '0';
    else
      s2_tempI <= '1';
    end if;

    s1_priority <= s1_tempI & s1_rDirty & s1_rRecent;
    s2_priority <= s2_tempI & s2_rDirty & s2_rRecent;
    -- nextstate case stmt
    case currState is
      when idle =>
        if(halt = '1') then
          nextState <= halt_check1;
        else
          if((t_chosenHit = '0' and (dmemREN = '1' or dmemWEN = '1'))) then
            -- if miss
            -- gevict somethin
            if(to_integer(unsigned(s1_priority)) <= to_integer(unsigned(s2_priority))) then
              -- choose s1
              if(s1_priority(1) = '1') then
                -- if dirty
                nextState <= s1_wb1;
              else
                nextState <= s1_snoop;
              end if;
            else
              -- choose s2
              if(s2_priority(1) = '1') then
                -- if dirty
                nextState <= s2_wb1;
              else
                nextState <= s2_snoop;
              end if;
            end if;
          elsif((t_chosenHit = '1' and t_chosenMSI = co_S and dmemWEN = '1')) then
            nextState <= busUpgrade;
          end if;
        end if;
      when busUpgrade =>
        if(RxBusResp /= bus_rxnop) then
          nextState <= idle;
        end if;
      when s1_snoop =>
        if(RxBusResp = bus_flushNF) then
          nextState <= s1_read1;
        elsif(RxBusResp = bus_flush) then
          nextState <= idle;
        end if;
      when s2_snoop =>
        if(RxBusResp = bus_flushNF) then
          nextState <= s2_read1;
        elsif(RxBusResp = bus_flush) then
          nextState <= idle;
        end if;
      when s1_wb1 =>
        if(arbWait = '0') then
          nextState <= s1_wb2;
        else
          nextState <= s1_wb1;
        end if;
      when s1_wb2 =>
        if(arbWait = '0') then
          nextState <= s1_snoop;
        else
          nextState <= s1_wb2;
        end if;
      when s1_read1 =>
        if(arbWait = '0') then
          nextState      <= s1_read2;
          t_readDataNext <= arbReadData;
        else
          nextState <= s1_read1;
        end if;
      when s1_read2 =>
        if(arbWait = '0') then
          nextState <= idle;
        else
          nextState <= s1_read2;
        end if;
      when s2_wb1 =>
        if(arbWait = '0') then
          nextState <= s2_wb2;
        else
          nextState <= s2_wb1;
        end if;
      when s2_wb2 =>
        if(arbWait = '0') then
          nextState <= s2_snoop;
        else
          nextState <= s2_wb2;
        end if;
      when s2_read1 =>
        if(arbWait = '0') then
          nextState      <= s2_read2;
          t_readDataNext <= arbReadData;
        else
          nextState <= s2_read1;
        end if;
      when s2_read2 =>
        if(arbWait = '0') then
          nextState <= idle;
        else
          nextState <= s2_read2;
        end if;
      when halt_s1wb1 =>
        if(arbWait = '0') then
          nextState <= halt_s1wb2;
        else
          nextState <= halt_s1wb1;
        end if;
      when halt_s1wb2 =>
        if(arbWait = '0') then
          nextState <= halt_check2;
        else
          nextState <= halt_s1wb2;
        end if;
      when halt_s2wb1 =>
        if(arbWait = '0') then
          nextState <= halt_s2wb2;
        else
          nextState <= halt_s2wb1;
        end if;
      when halt_s2wb2 =>
        if(arbWait = '0') then
          nextState <= halt_inc;
        else
          nextState <= halt_s2wb2;
        end if;
      when halt_inc =>
        if(halt_index = "1111") then
          nextState <= halt_halted;
        else
          nextState      <= halt_check1;
          halt_indexNext <= halt_index + '1';
        end if;
      when halt_check1 =>
        if(s1_priority(1) = '1' and s1_rMSI /= co_I) then
          -- if dirty
          nextState <= halt_s1wb1;
        else
          nextState <= halt_check2;
        end if;
      when halt_check2 =>
        if(s2_priority(1) = '1' and s2_rMSI /= co_I) then
          -- if dirty
          nextState <= halt_s2wb1;
        else
          nextState <= halt_inc;
        end if;
      when halt_halted =>
        nextState <= halt_halted;
      when others =>
        nextState <= idle;
    end case;
  end process nexttstate;

  -- dcache state machine output logic
  outp : process (currState, dmemREN, dmemWEN, dmemAddr, dmemWriteData, s1_rdat, s2_rdat, s1_rHit, s2_rHit, s1_rDirty, s2_rDirty, s1_rRecent, s2_rRecent, s1_tagOut, s2_tagOut, t_tag, t_index, halt_index, arbWait, arbReadData, t_chosenHit, t_wordSelect, t_readData, RxBusResp, t_chosenMSI, t_chosenSet, RxBusData)
  begin
    s1_index     <= t_index;
    s2_index     <= t_index;
    -- to CPU
    --dmemReadData <= x"00000000";
    dmemWait     <= '0';
    -- to Arbiter
    arbREN       <= '0';
    arbWEN       <= '0';
    t_arbAddr    <= x"00000000";
    arbWriteData <= x"00000000";
    -- to cache sets
    s1_wdat      <= x"0000000000000000";
    s2_wdat      <= x"0000000000000000";
    s1_wDirty    <= '0';
    s2_wDirty    <= '0';
    s1_datWEN    <= '0';
    s2_datWEN    <= '0';
    s1_wRecent   <= '0';
    s2_wRecent   <= '0';
    s1_recentWEN <= '0';
    s2_recentWEN <= '0';
    halt_out     <= '0';
    -- to bus
    TxBusOp      <= bus_txnop;
    TxBusAddr    <= x"00000000";
    -- msi
    s1_MSIWEN    <= '0';
    s2_MSIWEN    <= '0';
    s2_wMSI      <= co_I;
    s1_wMSI      <= co_I;
    -- output case stmt
    case currState is
      when idle =>
        if(t_chosenHit = '1' and t_chosenMSI = co_S and dmemWEN = '1') then
          dmemWait <= '1';
        elsif(dmemWEN = '1' or dmemREN = '1') then
          dmemWait <= (not t_chosenHit) or arbWait;
        else
          dmemWait <= '0';
        end if;
        s2_recentWEN <= dmemWEN or dmemREN;
        s1_recentWEN <= dmemWEN or dmemREN;
        if(t_chosenSet = '1') then
          s2_wDirty  <= dmemWEN and t_chosenHit;
          s2_datWEN  <= dmemWEN and t_chosenHit;
          s2_wRecent <= '1';
          s1_wRecent <= '0';
          if(t_wordSelect = '1') then
            s2_wdat <= s2_rdat(63 downto 32) & dmemWriteData;
          else
            s2_wdat <= dmemWriteData & s2_rdat(31 downto 0);
          end if;
        else
          s1_wDirty  <= dmemWEN and t_chosenHit;
          s1_datWEN  <= dmemWEN and t_chosenHit;
          s1_wRecent <= '1';
          s2_wRecent <= '0';
          if(t_wordSelect = '1') then
            s1_wdat <= s1_rdat(63 downto 32) & dmemWriteData;
          else
            s1_wdat <= dmemWriteData & s1_rdat(31 downto 0);
          end if;
        end if;
      when busUpgrade =>
        dmemWait  <= '1';
        TxBusAddr <= t_tag & t_index & "000";
        TxBusOp   <= bus_RdX;
        if(RxBusResp /= bus_rxnop) then
          if(t_chosenSet = '1') then
            s2_wMSI   <= co_M;
            s2_MSIWEN <= '1';
          else
            s1_wMSI   <= co_M;
            s1_MSIWEN <= '1';
          end if;
        end if;
      when s1_snoop =>
        dmemWait  <= '1';
        TxBusAddr <= t_tag & t_index & "000";
        if(RxBusResp = bus_flush) then
          s1_wdat   <= RxBusData;
          s1_wDirty <= '0';
          s1_datWEN <= '1';
          -- change MSI state
          if(dmemREN = '1') then
            s1_wMSI <= co_S;
          elsif(dmemWEN = '1') then
            s1_wMSI <= co_M;
          end if;
          s1_MSIWEN <= '1';
        end if;
        if(dmemREN = '1') then
          TxBusOp <= bus_Rd;
        elsif(dmemWEN = '1') then
          TxBusOp <= bus_RdX;
        end if;
      when s2_snoop =>
        dmemWait  <= '1';
        TxBusAddr <= t_tag & t_index & "000";
        if(RxBusResp = bus_flush) then
          s2_wdat   <= RxBusData;
          s2_wDirty <= '0';
          s2_datWEN <= '1';
          -- change MSI state
          if(dmemREN = '1') then
            s2_wMSI <= co_S;
          elsif(dmemWEN = '1') then
            s2_wMSI <= co_M;
          end if;
          s2_MSIWEN <= '1';
        end if;
        if(dmemREN = '1') then
          TxBusOp <= bus_Rd;
        elsif(dmemWEN = '1') then
          TxBusOp <= bus_RdX;
        end if;
      when s1_wb1 =>                    -- write back ub
        dmemWait     <= '1';
        arbREN       <= '0';
        arbWEN       <= '1';
        t_arbAddr    <= s1_tagOut & t_index & "000";
        arbWriteData <= s1_rdat(63 downto 32);
      when s1_wb2 =>                    -- write back lb
        dmemWait     <= '1';
        arbREN       <= '0';
        arbWEN       <= '1';
        t_arbAddr    <= s1_tagOut & t_index & "100";
        arbWriteData <= s1_rdat(31 downto 0);
      when s1_read1 =>                  -- read ub
        dmemWait  <= '1';
        arbREN    <= '1';
        arbWEN    <= '0';
        t_arbAddr <= t_tag & t_index & "000";
      when s1_read2 =>                  -- read lb
        dmemWait  <= '1';
        arbREN    <= '1';
        arbWEN    <= '0';
        t_arbAddr <= t_tag & t_index & "100";
        s1_wdat   <= t_readData & arbReadData;
        s1_wDirty <= '0';
        s1_datWEN <= not arbWait;
        -- change MSI state
        if(dmemREN = '1') then
          s1_wMSI <= co_S;
        elsif(dmemWEN = '1') then
          s1_wMSI <= co_M;
        end if;
        s1_MSIWEN <= '1';
      when s2_wb1 =>                    -- write back ub
        dmemWait     <= '1';
        arbREN       <= '0';
        arbWEN       <= '1';
        t_arbAddr    <= s2_tagOut & t_index & "000";
        arbWriteData <= s2_rdat(63 downto 32);
      when s2_wb2 =>                    -- write back lb
        dmemWait     <= '1';
        arbREN       <= '0';
        arbWEN       <= '1';
        t_arbAddr    <= s2_tagOut & t_index & "100";
        arbWriteData <= s2_rdat(31 downto 0);
      when s2_read1 =>
        dmemWait  <= '1';
        arbREN    <= '1';
        arbWEN    <= '0';
        t_arbAddr <= t_tag & t_index & "000";
      when s2_read2 =>
        dmemWait  <= '1';
        arbREN    <= '1';
        arbWEN    <= '0';
        t_arbAddr <= t_tag & t_index & "100";
        s2_wdat   <= t_readData & arbReadData;
        s2_wDirty <= '0';
        s2_datWEN <= not arbWait;
        -- change MSI state
        if(dmemREN = '1') then
          s2_wMSI <= co_S;
        elsif(dmemWEN = '1') then
          s2_wMSI <= co_M;
        end if;
        s2_MSIWEN <= '1';
      when halt_halted =>
        halt_out <= '1';
      when halt_check1 =>
        s1_index <= halt_index;
      when halt_check2 =>
        s2_index <= halt_index;
      when halt_s1wb1 =>                -- write back ub
        dmemWait     <= '1';
        arbREN       <= '0';
        arbWEN       <= '1';
        t_arbAddr    <= s1_tagOut & halt_index & "000";
        arbWriteData <= s1_rdat(63 downto 32);
        s1_index     <= halt_index;
      when halt_s1wb2 =>                -- write back lb
        dmemWait     <= '1';
        arbREN       <= '0';
        arbWEN       <= '1';
        t_arbAddr    <= s1_tagOut & halt_index & "100";
        arbWriteData <= s1_rdat(31 downto 0);
        s1_index     <= halt_index;
      when halt_s2wb1 =>                -- write back ub
        dmemWait     <= '1';
        arbREN       <= '0';
        arbWEN       <= '1';
        t_arbAddr    <= s2_tagOut & halt_index & "000";
        arbWriteData <= s2_rdat(63 downto 32);
        s2_index     <= halt_index;
      when halt_s2wb2 =>                -- write back lb
        dmemWait     <= '1';
        arbREN       <= '0';
        arbWEN       <= '1';
        t_arbAddr    <= s2_tagOut & halt_index & "100";
        arbWriteData <= s2_rdat(31 downto 0);
        s2_index     <= halt_index;
      when others =>
        dmemWait <= ((dmemWEN or dmemREN) and not t_chosenHit) or arbWait;
        
    end case;
  end process;
  
  
end dcache_ctrl_arch;
